package com.yuyou.fn.educational.service.impl;

import com.github.wens.framework.service.impl.SuperServiceImpl;
import com.github.wens.mybatisplus.examples.Example;
import com.github.wens.mybatisplus.plugins.Page;
import com.yuyou.fn.common.exception.BusException;
import com.yuyou.fn.common.util.*;
import com.yuyou.fn.educational.entity.CourseClass;
import com.yuyou.fn.educational.entity.DiscountCode;
import com.yuyou.fn.educational.mapper.DiscountCodeMapper;
import com.yuyou.fn.educational.service.IDiscountCodeService;
import com.yuyou.fn.educational.vo.DiscountCodeCreateVo;
import com.yuyou.fn.educational.vo.DiscountCodeQueryVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 *
 * DiscountCode 表数据服务层接口实现类
 *
 */
@Service
public class DiscountCodeServiceImpl extends SuperServiceImpl<DiscountCodeMapper, DiscountCode,Long> implements IDiscountCodeService {

    @Resource
    private RedisTemplate<String,String> redisTemplate;

    @Override
    public void createDiscountCode(DiscountCodeCreateVo discountCodeCreateVo) {
        if (discountCodeCreateVo.getAmount()<=0){
            throw new BusException("数量必须大于0");
        }
        if (discountCodeCreateVo.getDiscountType() == 0 && discountCodeCreateVo.getDiscountAmount().doubleValue()<=0d){
            throw new BusException("优惠金额必须大于0");
        }
        if (discountCodeCreateVo.getOrderThresholdAmount().doubleValue()<0d){
            throw new BusException("最低金额必须大于等于0");
        }
        if (discountCodeCreateVo.getEffectiveEndTimestamp()<discountCodeCreateVo.getEffectiveStartTimestamp()){
            throw new BusException("结束时间必须大于开始时间");
        }
        if(!redisTemplate.hasKey("discount:code")){
            redisTemplate.opsForValue().set("discount:code","1234");
        }
        if (discountCodeCreateVo.getDiscountType() == 1
                && (discountCodeCreateVo.getDiscountAmount().doubleValue() <= 0 || discountCodeCreateVo.getDiscountAmount().doubleValue() > 1)){
            throw new BusException("优惠折扣折扣范围：0 < “所填折扣” <= 1 ");
        }

        Long num = redisTemplate.opsForValue().increment("discount:code",discountCodeCreateVo.getAmount() );

        List<DiscountCode> list = new ArrayList<>(discountCodeCreateVo.getAmount());
        Date now = TimeUtils.now();
        for(int i = 0 ; i < discountCodeCreateVo.getAmount() ; i++ ){
            String code = Utils.to62(Long.valueOf(( num - i ) + RandomUtils.generateStringNumber(5)));
            DiscountCode discountCode = new DiscountCode();
            BeanUtils.copyProperties(discountCode,discountCodeCreateVo);
            discountCode.setCode(code);
            discountCode.setEnableStatus(1);
            discountCode.setUsedStatus(0);
            discountCode.setEffectiveStartTime(new Date(discountCodeCreateVo.getEffectiveStartTimestamp()));
            discountCode.setEffectiveEndTime(new Date(discountCodeCreateVo.getEffectiveEndTimestamp()));
            discountCode.setCreateTime(now);
            discountCode.setUpdateTime(now);
            list.add(discountCode);
            if (list.size()>=500){
                insertBatch(list);
                list.clear();
            }
        }
        if (list.size()>0){
            insertBatch(list);
        }
    }

    @Override
    public Page<DiscountCode> findByQuery(DiscountCodeQueryVo discountCodeQueryVo,Integer pageNo , Integer pageSize ) {

        Example<DiscountCode> example = DiscountCode.createExample();
        example.orderBy("createTime").desc();
        Example.Criteria criteria = example.createCriteria();
        CriteriaUtils.fillCondition(criteria,discountCodeQueryVo);

        if(discountCodeQueryVo.getEffectStatus() != null ){
            if(discountCodeQueryVo.getEffectStatus() == 0 ){
                criteria.andCondition(" ( effective_start_time > now() or effective_start_time > now() ) ");
            }else{
                criteria.andLessThan("effectiveStartTime",TimeUtils.now() ).andGreaterThan("effectiveEndTime",TimeUtils.now());
            }
        }
        return findPageByExample(example,pageNo,pageSize);
    }

    @Override
    public void updateEnableStatus(List<Long> discountCodeIds,Integer enableStatus) {
        Example<DiscountCode> example = DiscountCode.createExample();
        example.createCriteria().andIn("discountCodeId",discountCodeIds);
        DiscountCode discountCode = new DiscountCode() ;
        discountCode.setEnableStatus(enableStatus);
        updateSelectiveByExample(discountCode,example);
    }

    @Override
    public DiscountCode checkCode(Long courseOrderId , String discountCode , BigDecimal orderPayableAmount , List<CourseClass> courseClasses) {

        if(isLock( courseOrderId, discountCode) ){
            throw new BusException("此优惠码暂时锁定，请稍后再试");
        }

        DiscountCode discountCodeObj = checkDiscountCodeStatus(discountCode);

        if(BigDecimals.compare(discountCodeObj.getOrderThresholdAmount(),orderPayableAmount) > 0 ){
            throw new BusException("不满足最低消费（"+orderPayableAmount+"）");
        }

        String error = "该订单存在不满足使用优惠码的课程，请剔除后再报名！（不满足课程：%s）";

        for(CourseClass courseClass : courseClasses ){

            if(  !discountCodeObj.getAreaTeamId().equals(courseClass.getAreaTeamId()) ){
                throw new BusException(String.format(error,courseClass.getClassName()));
            }


            if(StringUtils.isNotEmpty(discountCodeObj.getBusTeamIds()) && !discountCodeObj.getBusTeamIds().contains(String.valueOf(courseClass.getBusTeamId()))){
                throw new BusException(String.format(error,courseClass.getClassName()));
            }

            if(StringUtils.isNotEmpty(discountCodeObj.getPeriodIds()) && !discountCodeObj.getPeriodIds().contains(String.valueOf(courseClass.getPeriodId()))){
                throw new BusException(String.format(error,courseClass.getClassName()));
            }

            if(StringUtils.isNotEmpty(discountCodeObj.getProductIds()) && !discountCodeObj.getProductIds().contains(String.valueOf(courseClass.getProductId()))){
                throw new BusException(String.format(error,courseClass.getClassName()));
            }

            if( StringUtils.isNotEmpty(discountCodeObj.getCourseTemplateIds() ) && !discountCodeObj.getCourseTemplateIds().contains(String.valueOf(courseClass.getCourseTemplateId()))){
                throw new BusException(String.format(error,courseClass.getClassName()));
            }

            if(StringUtils.isNotEmpty(discountCodeObj.getSubjectIds() ) && !discountCodeObj.getSubjectIds().contains(String.valueOf(courseClass.getSubjectId()))){
                throw new BusException(String.format(error,courseClass.getClassName()));
            }

            if(StringUtils.isNotEmpty(discountCodeObj.getGradeIds() ) && !discountCodeObj.getGradeIds().contains(String.valueOf(courseClass.getGradeId()))){
                throw new BusException(String.format(error,courseClass.getClassName()));
            }
        }

        return discountCodeObj ;
    }

    @Override
    public DiscountCode checkDiscountCodeStatus(String discountCode) {
        DiscountCode discountCodeObj = findByDiscountCode(discountCode);

        if(discountCodeObj == null ){
            throw new BusException("输入优惠码不存在:" + discountCode );
        }

        if(discountCodeObj.getUsedStatus() == DiscountCode.UsedStatusEnum.已使用.ordinal() ){
            throw new BusException("输入优惠码已经被使用过");
        }

        if(discountCodeObj.getEnableStatus() == DiscountCode.EnableStatusEnum.禁用.ordinal() || discountCodeObj.getEffectiveStartTime().after(TimeUtils.now()) || discountCodeObj.getEffectiveEndTime().before(TimeUtils.now()) ){
            throw new BusException("输入优惠码已作废或已过期");
        }
        return discountCodeObj;
    }

    @Transactional
    @Override
    public void updateUsedStatus(String discountCode) {
        unlock(discountCode);
        DiscountCode discountCodeObj = this.checkDiscountCodeStatus(discountCode);
        Example<DiscountCode> example = DiscountCode.createExample();
        example.createCriteria().andEqualTo("discountCodeId" ,discountCodeObj.getDiscountCodeId() );
        DiscountCode update = new DiscountCode() ;
        update.setUsedStatus(DiscountCode.UsedStatusEnum.已使用.ordinal());
        if( !updateSelectiveByExample(update,example)){
            throw new BusException("输入优惠码已经被使用过");
        }
    }

    private DiscountCode findByDiscountCode(String discountCode) {
        Example<DiscountCode> example = DiscountCode.createExample();
        example.createCriteria().andEqualTo("code",discountCode);
        return findOneByExample(example);
    }


    private boolean isLock(Long courseOrderId,String discountCode) {
        String lockCourseOrderId = (String)redisTemplate.opsForHash().get("discount_code_lock", discountCode);
        if(lockCourseOrderId != null && !lockCourseOrderId.equals(String.valueOf(courseOrderId))){
            return true ;
        }
        return false ;

    }

    @Override
    public void lock(Long courseOrderId,String discountCode) {
        redisTemplate.opsForHash().put("discount_code_lock", discountCode,String.valueOf(courseOrderId));
    }

    @Override
    public void unlock(String discountCode) {
        redisTemplate.opsForHash().delete("discount_code_lock",discountCode,String.valueOf(System.currentTimeMillis()));
    }
}